package com.da.redis.controller;

import java.util.UUID;

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author JokerDa.
 * @date 2020/12/31 15:22
 * 单机版加锁:
 * synchronized:必须等里面的业务完成才能释放锁，容易造成线程积压
 * ReentrantLock:可以使用trylock关键字申明抢占锁时间，抢不到可以放弃或者干其他事情
 */
@RestController
public class GoodController {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Value("${server.port}")
    private String port;
    private final String lock = "MyLock";
    @Autowired
    private Redisson redisson;


    /*@GetMapping("buyGoods")
    public String buyGoods() throws Exception {
        String value = UUID.randomUUID().toString() + Thread.currentThread().getName();
        try {
            Boolean flag = redisTemplate.opsForValue().setIfAbsent(lock, value, 10L, TimeUnit.SECONDS);
            if (!flag) {
                return "抢锁失败！";
            }

            String result = redisTemplate.opsForValue().get("goods:001");
            int goodNumber = StringUtils.isEmpty(result) ? 0 : Integer.parseInt(result);
            if (goodNumber > 0) {
                int resultNumber = goodNumber - 1;
                redisTemplate.opsForValue().set("goods:001", String.valueOf(resultNumber));
                System.out.println("成功买到商品，库存还剩下：" + resultNumber + " 件\t服务提供端口：" + port);

                return "成功买到商品，库存还剩下：" + resultNumber + " 件\t服务提供端口：" + port;
            } else {
                System.out.println("商品已经卖完/活动结束/调用超市，欢迎下次光临" + "\t服务提供端口：" + port);
            }
        } finally {
            // 保证只能删除自己加的锁，但是是非原子的操作,可以使用lua脚本或者redis的事务
            //if (value.equals(redisTemplate.opsForValue().get(lock))) {
            //    redisTemplate.delete(lock);
            //}

            // 使用事务
            //while (true) {
            //    redisTemplate.watch(lock);
            //    if (value.equals(redisTemplate.opsForValue().get(lock))) {
            //        redisTemplate.setEnableTransactionSupport(true);
            //        redisTemplate.multi();
            //        redisTemplate.delete(lock);
            //        List<Object> list = redisTemplate.exec();
            //        if (list == null) {
            //            continue;
            //        }
            //    }
            //    redisTemplate.unwatch();
            //    break;
            //}

            // 使用lua脚本
            try (Jedis jedis = JedisUtils.getJedis()) {
                String script = "if redis.call('get',KEYS[1]) == ARGV[1] "
                    + "then "
                    + "    return redis.call('del',KEYS[1]) "
                    + "else "
                    + "    return 0 "
                    + "end";
                Object o = jedis.eval(script, Collections.singletonList(lock), Collections.singletonList(value));
                if ("1".equals(o.toString())) {
                    System.out.println("---delete redis lock ok");
                } else {
                    System.out.println("---delete redis lock error");
                }
            }
        }
        return "商品已经卖完/活动结束/调用超市，欢迎下次光临" + "\t服务提供端口：" + port;
    }*/

    @GetMapping("buyGoods")
    public String buyGoods() throws Exception {
        String value = UUID.randomUUID().toString() + Thread.currentThread().getName();
        RLock redissonLock = redisson.getLock(this.lock);
        redissonLock.lock();
        try {
            String result = redisTemplate.opsForValue().get("goods:001");
            int goodNumber = StringUtils.isEmpty(result) ? 0 : Integer.parseInt(result);
            if (goodNumber > 0) {
                int resultNumber = goodNumber - 1;
                redisTemplate.opsForValue().set("goods:001", String.valueOf(resultNumber));
                System.out.println("成功买到商品，库存还剩下：" + resultNumber + " 件\t服务提供端口：" + port);

                return "成功买到商品，库存还剩下：" + resultNumber + " 件\t服务提供端口：" + port;
            } else {
                System.out.println("商品已经卖完/活动结束/调用超市，欢迎下次光临" + "\t服务提供端口：" + port);
            }
        } finally {
            if (redissonLock.isLocked() && redissonLock.isHeldByCurrentThread()) {
                redissonLock.unlock();
            }
        }
        return "商品已经卖完/活动结束/调用超市，欢迎下次光临" + "\t服务提供端口：" + port;
    }
}
